package com.hse.network;

import com.hse.application.ApplicationLayerException;
import com.hse.application.ApplicationMacStackLayer;
import com.hse.application.MacStackLayerClient;
import com.meshnetics.gb.stack.mac.primitives.MACResetConfirm;
import com.meshnetics.gb.stack.mac.primitives.MACResetRequest;
import com.meshnetics.gb.stack.mac.type.MACStatus;
import com.meshnetics.gb.stack.mac.type.PANDescriptor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Assert;
import org.junit.Test;

/**
 * Created by IntelliJ IDEA.
 * User: Lexa
 * Date: May 25, 2009
 * Time: 10:00:48 PM
 * To change this template use File | Settings | File Templates.
 */
public class MacUserLayerTester {
    private static final Log log = LogFactory.getLog(MacUserLayerTester.class);
    private final short PAN_ID = 12345;

    @Test(timeout = 5000)
    public void testStartAndExecuteInitCommand() throws InstantiationException, ApplicationLayerException {
        ApplicationMacStackLayer mac = new ApplicationMacStackLayer(TestConfigurator.PORT_NAME_1);
        try {
            MACResetRequest macResetRequest = new MACResetRequest(true);
            MACResetConfirm macResetConfirm = (MACResetConfirm) mac.execute(macResetRequest);
            log.info("macResetConfirm: " + macResetConfirm);
            Assert.assertEquals(MACStatus.SUCCESS, macResetConfirm.getStatus());
        } finally {
            mac.stop();
        }
    }

    @Test(timeout = 5000)
    public void testInitDevice() throws InstantiationException, ApplicationLayerException {
        ApplicationMacStackLayer mac = new ApplicationMacStackLayer(TestConfigurator.PORT_NAME_1);
        try {
            mac.init((long) 0);
        } finally {
            mac.stop();
        }
    }

    @Test(timeout = 5000)
    public void testScanEmptyNetworks() throws InstantiationException, ApplicationLayerException {
        ApplicationMacStackLayer mac = new ApplicationMacStackLayer(TestConfigurator.PORT_NAME_1);
        try {
            mac.init((long) 0);
            PANDescriptor[] networks = mac.scan();
            Assert.assertEquals(0, networks.length);
        } finally {
            mac.stop();
        }
    }

    @Test(timeout = 5000)
    public void testCreateNetwork() throws InstantiationException, ApplicationLayerException {
        ApplicationMacStackLayer mac = new ApplicationMacStackLayer(TestConfigurator.PORT_NAME_1);
        try {
            mac.init((long) 0);
            mac.createNetwork(PAN_ID);
        } finally {
            mac.stop();
        }
    }

    @Test(timeout = 5000, expected = ApplicationLayerException.class)
    public void testConnect() throws InstantiationException, ApplicationLayerException {
        ApplicationMacStackLayer mac = new ApplicationMacStackLayer(TestConfigurator.PORT_NAME_1);
        try {
            mac.init((long) 0);
            mac.connect(PAN_ID);
        } finally {
            mac.stop();
        }
    }

    @Test(timeout = 5000)
    public void testClientScanNetwork() throws InstantiationException, ApplicationLayerException {
        ApplicationMacStackLayer coordinatorMac = new ApplicationMacStackLayer(TestConfigurator.PORT_NAME_1);
        try {
            coordinatorMac.init((long) 0);
            coordinatorMac.createNetwork(PAN_ID);
        } catch (Exception e) {
            coordinatorMac.stop();
            Assert.fail();
        }

        ApplicationMacStackLayer clientMac = new ApplicationMacStackLayer(TestConfigurator.PORT_NAME_2);
        try {
            clientMac.init((long) 1);
            PANDescriptor[] networks = clientMac.scan();
            Assert.assertEquals(1, networks.length);
        } finally {
            clientMac.stop();
            coordinatorMac.stop();
        }
    }


    @Test(timeout = 5000)
    public void testClientConnectToNetwork() throws InstantiationException, ApplicationLayerException {
        ApplicationMacStackLayer coordinatorMac = new ApplicationMacStackLayer(TestConfigurator.PORT_NAME_1);
        try {
            coordinatorMac.init((long) 0);
            coordinatorMac.createNetwork(PAN_ID);
        } catch (Exception e) {
            coordinatorMac.stop();
            Assert.fail();
        }

        ApplicationMacStackLayer clientMac = new ApplicationMacStackLayer(TestConfigurator.PORT_NAME_2);
        try {
            clientMac.init((long) 1);
            clientMac.connect(PAN_ID);
        } finally {
            clientMac.stop();
            coordinatorMac.stop();
        }
    }

    @Test(timeout = 5000)
    public void testCoordinatorAcceptConnection() throws InstantiationException, ApplicationLayerException {
        ApplicationMacStackLayer coordinatorMac = new ApplicationMacStackLayer(TestConfigurator.PORT_NAME_1);
        try {
            coordinatorMac.init((long) 0);
            coordinatorMac.createNetwork(PAN_ID);
        } catch (Exception e) {
            coordinatorMac.stop();
            Assert.fail();
        }

        ApplicationMacStackLayer clientMac = new ApplicationMacStackLayer(TestConfigurator.PORT_NAME_2);
        try {
            final Long macAddress = (long) 546;
            clientMac.init(macAddress);
            clientMac.connect(PAN_ID);
            MacStackLayerClient endDevice = coordinatorMac.acceptEndDevice(5000);
            Assert.assertEquals(macAddress, endDevice.getDeviceAddress());
        } finally {
            clientMac.stop();
            coordinatorMac.stop();
        }
    }

    @Test(timeout = 5000)
    public void testCoordinatorAcceptNoClients() throws InstantiationException, ApplicationLayerException {
        ApplicationMacStackLayer coordinatorMac = new ApplicationMacStackLayer(TestConfigurator.PORT_NAME_1);
        try {
            coordinatorMac.init((long) 0);
            coordinatorMac.createNetwork(PAN_ID);
            try {
                coordinatorMac.acceptEndDevice(3000);
            } catch (ApplicationLayerException ex) {
                Assert.assertEquals(0, ex.getMessage().indexOf("Time out"));
            }
        } finally {
            coordinatorMac.stop();
        }
    }

    @Test()
    public void testSendReciveData() throws InstantiationException, ApplicationLayerException {
        final long coordinatorAddress = (long) 0;
        ApplicationMacStackLayer coordinatorMac = new ApplicationMacStackLayer(TestConfigurator.PORT_NAME_1);
        try {
            coordinatorMac.init(coordinatorAddress);
            coordinatorMac.createNetwork(PAN_ID);
        } catch (Exception e) {
            coordinatorMac.stop();
            Assert.fail();
        }

        ApplicationMacStackLayer clientMac = new ApplicationMacStackLayer(TestConfigurator.PORT_NAME_2);
        try {
            final Long macAddress = (long) 546;
            clientMac.init(macAddress);
            clientMac.connect(PAN_ID);
            MacStackLayerClient endDevice = coordinatorMac.acceptEndDevice(5000);
            byte[] sendData1 = "HELLO WORLD!".getBytes();
            final Short clientAddress = endDevice.getShortAddress();
            clientMac.send(PAN_ID, clientAddress, (short) 0, sendData1);
            byte[] recvData1 = coordinatorMac.recv(PAN_ID, clientAddress, (short) 0);
            Assert.assertArrayEquals(sendData1, recvData1);

            byte[] sendData2 = "HELLO WORLD!".getBytes();
            coordinatorMac.send(PAN_ID, (short) 0, clientAddress, sendData2);
            byte[] recvData2 = clientMac.recv(PAN_ID, (short) 0, clientAddress);
            Assert.assertArrayEquals(sendData2, recvData2);
        } finally {
            clientMac.stop();
            coordinatorMac.stop();
        }
    }
}
